<?php

namespace origin;

/**
 * 反射类
 * @author dece <decezz@qq.com>
 */
class Reflections
{
    // 过滤方法列表
    public static $filter = [];

    // 类文档生效字段
    public static $class_doc_field = [
        'title'     => '',
        'explain'   => '',
        'version'   => 'v1.0.0',
    ];

    // 方法文档生效字段
    public static $method_doc_field = [
        'url'           => '',
        'title'         => '',
        'version'       => 'v1.0.0',
        'method'        => '',
        'param'         => [],
        'return'        => [],
    ];

    /**
     * 获取接口文档
     * @param   array   yes   class_arr     类的数组
     * @param   array   no    filter_arr    过滤方法
     * @return  array
     */
    public static function getDocument( $class_arr , $filter_arr = [] )
    {
        // 反射对象列表
        $result = [];
        // 生效字段
        $field_arr = self::$class_doc_field;
        // 遍历类
        foreach ($class_arr as $class) {
            // 定义数组
            $doc_arr = $field_arr;
            // 类的映射
            $reflect = new \ReflectionClass($class);
            // 获取类的注释
            $class_doc = $reflect->getDocComment();
            
            if ($class_doc !== false) {
                // 正则匹配
                preg_match_all("/@.*?/U", $class_doc, $class_doc_arr);
                // 没有匹配到结果的方法跳过
                if (is_array($class_doc_arr) && count($class_doc_arr[0]) > 0) {
                    
                    foreach ($class_doc_arr[0] as $str) {
                        // 注释行转数组
                        $arr = explode("@|@", preg_replace("/[\s]+/", "@|@", $str));
                        // 匹配到参数
                        $match = self::match_field($field_arr, $arr);
                        // 合并参数
                        $doc_arr = array_merge($doc_arr, $match);
                    }
                }
            }
            // 放入类命名空间
            $doc_arr['namespace'] = $reflect->getName();
            // 获取方法文档
            $doc_arr['api'] = self::getMethodDocument($reflect, $filter_arr);
            // 数据赋值
            $result[] = $doc_arr;
        }
        return $result;
    }

    /**
     * 获取类中方法文档
     * @param   string      yes     reflect       类的数组
     * @param   array       no      filter_arr    过滤方法
     * @return  array
     */
    public static function getMethodDocument( $reflect , $filter_arr = [] )
    {
        // 反射对象列表
        $result = [];
        // 类中所有的公共方法
        $pub_method = $reflect->getMethods(\ReflectionMethod::IS_PUBLIC);
        // 生效字段
        $field_arr = self::$method_doc_field;
        // 遍历方法
        foreach ($pub_method as $method) {
            // 定义数组
            $method_arr = $field_arr;
            // 放入路径
            $method_arr['location'] = $reflect->getName() .'::'. $method->name;
            // 过滤方法
            if (in_array($method->name, $filter_arr)) {
                continue;
            }
            // 方法的注释
            $comment = $reflect->getMethod($method->name)->getDocComment();
            // 方法的注释不存在
            if ($comment == false) {
                continue;
            }
            // 正则匹配
            preg_match_all("/@.*?/U", $comment, $comment_arr);
            // 没有匹配到结果的方法跳过
            if (is_array($comment_arr) && count($comment_arr[0]) > 0) {
                
                foreach ($comment_arr[0] as $str) {
                    // 注释行转数组
                    $param = explode("@|@", preg_replace("/[\s]+/", "@|@", $str));
                    // 匹配到参数
                    $match = self::match_field($field_arr, $param);
                    // 参数名称
                    $key = array_keys($match);
                    // 检查下标
                    $key = isset($key[0]) ? $key[0] : '' ;
                    // 多参数处理
                    if ($key == 'param' || $key == 'return') {
                        // 合并之前的参数
                        $match[$key] = array_merge($method_arr[$key], $match[$key]);
                    }
                    // 合并参数
                    $method_arr = array_merge($method_arr, $match);
                }
            }
            $result[] = $method_arr;
        }
        return $result;
    }

    /**
     * 匹配参数
     * @param   array     yes     field_arr  生效字段
     * @param   array     yes     array      匹配的数组
     * @return  array
     */
    public static function match_field( $field_arr , $data = [] )
    {
        // 空数组
        $array = [];
        // 匹配相同的字段
        foreach ($field_arr as $key => $val) {
            // 字段没匹配到
            if (!in_array('@' . $key, $data)) {
                continue;
            }
            switch ('@' . $key) {
                case '@param':
                    $array[$key][] = $data;
                    break;

                case '@return':
                    $array[$key][] = $data;
                    break;

                case '@method':
                    $array[$key] = explode(',', $data[1]);
                    break;

                default:
                    $array[$key] = $data[1];
                    break;
            }
        }
        return $array;
    }
}